package owlapps2012.owlToSql.base;

import java.io.File;
import java.util.regex.Matcher;

import org.apache.log4j.Logger;
import org.semanticweb.owlapi.model.OWLClassExpression;

import owlapps2012.owlToSql.events.p4.EventsToSQLP4Transformer;

import uk.ac.manchester.cs.owl.owlapi.mansyntaxrenderer.ManchesterOWLSyntaxOWLObjectRendererImpl;

/**
* Author: Piotr Nowara<br>
* piotrnowara@gmail.com<br>
* code made available under Mozilla Public License (http://www.mozilla.org/MPL/MPL-1.1.html)<br>
* copyright 2013, Piotr Nowara<br>
*/
public class CompoundCategoryTransformer extends Transformer
{
	
	private static Logger log = Logger.getLogger(CompoundCategoryTransformer.class);
//	protected static final String catSQLString = " EXISTS (SELECT 1 FROM {APP_SCHEMA}.{RESULT_TABLE} A JOIN {APP_SCHEMA}.PROCESS B ON B.ID = A.PROCESS_ID JOIN {APP_SCHEMA}.CATEGORY C ON C.ID = B.CATEGORY_ID WHERE C.NAME = '{CATEGORY_NAME}') ";
	protected static final String catSQLString = " EXISTS (SELECT 1 FROM {APP_SCHEMA}.{RESULT_TABLE} A JOIN {APP_SCHEMA}.PROCESS B ON B.ID = A.PROCESS_ID AND A.PROCESS_ID = (SELECT MAX(P.ID) FROM {APP_SCHEMA}.PROCESS P JOIN {APP_SCHEMA}.CATEGORY C ON C.ID = P.CATEGORY_ID WHERE C.NAME = '{CATEGORY_NAME}' AND P.STATUS = 2) WHERE S1L1.EVENT_ID = A.EVENT_ID) ";
	protected static final String baseSQL = "SELECT * FROM {APP_SCHEMA}.{RESULT_TABLE} S1L1 WHERE";
	protected DynamicDbAppConfig config;
	

	
	
	public CompoundCategoryTransformer(DynamicDbAppConfig config)
	{
		super(config);
		this.config = config;
	}
	
	
	public String transformOWLClassExpression(String expr) throws OwlToSqlTransformationException
	{
		String sql = baseSQL;
		log.info("Starting transformation of following exression: "+expr);
		doValidation(expr);
		String expressionToTransform = doPreprocessing(expr);
		

		
//		Matcher firstClassMatcher = TextProcessingUtils.compoundCategoryPatternFirstElement.matcher(expressionToTransform);
//		if(firstClassMatcher.find())
//		{
//			String notPart = firstClassMatcher.group(1);
//			String openingBrackets = firstClassMatcher.group(2);
//			String endingBrackets = firstClassMatcher.group(4);
//			String catName = firstClassMatcher.group(3);
//			openingBrackets = openingBrackets == null ? openingBrackets : "";
//			endingBrackets = endingBrackets == null ? endingBrackets : "";
//
//			if(notPart != null)
//				sql = baseSQLString.concat(notPart.toUpperCase()).concat(" ").concat(openingBrackets).concat(catSQLString.replaceAll("{CATEGORY_NAME}", catName)).concat(endingBrackets);
//			else
//				sql = baseSQLString.concat(openingBrackets).concat(catSQLString.replaceAll("{CATEGORY_NAME}", catName)).concat(endingBrackets);
//		}
//		else
//			throw new Exception("Illegal expression: "+expressionToTransform);
//		firstClassMatcher = null;
		
		String baseCategoryName = expressionToTransform.split(" ")[0];
		String baseTable = this.getResultsTableName(baseCategoryName);
		
		int count = 0;
		Matcher nextClassMatcher = TextProcessingUtils.compoundCategoryPatternNextElement.matcher(expressionToTransform);
		while(nextClassMatcher.find())
		{
			count++;
			String logicalOperator = nextClassMatcher.group(1);
			String notPart = nextClassMatcher.group(2);
			String openingBrackets = nextClassMatcher.group(3);
			String endingBrackets = nextClassMatcher.group(5);
			String catName = nextClassMatcher.group(4);
			openingBrackets = openingBrackets != null ? openingBrackets : "";
			endingBrackets = endingBrackets != null ? endingBrackets : "";
			if(count == 1)//the first class is always a base category that needs to be omitted from the WHERE list
			{
				if(logicalOperator.equals("or"))
					throw new OwlToSqlTransformationException("Illegal use of 'or': "+expressionToTransform);
				logicalOperator = "";
			}
			
//			if(count > 1 && logicalOperator == null)
//				throw new Exception("Illegal expression: "+expressionToTransform);
//			if(count == 1 && logicalOperator != null)
//				throw new Exception("Illegal expression: "+expressionToTransform);
//			System.out.println("LOG: "+logicalOperator);
			

			if(notPart != null)
				sql = sql.concat(logicalOperator.toUpperCase()).concat(" ").concat(notPart.toUpperCase()).concat(" ").concat(openingBrackets).concat(catSQLString.replaceAll("\\{CATEGORY_NAME\\}", catName)).concat(endingBrackets);
			else
				sql = sql.concat(logicalOperator.toUpperCase()).concat(openingBrackets).concat(catSQLString.replaceAll("\\{CATEGORY_NAME\\}", catName)).concat(endingBrackets);
		}
		
		if(count == 0)
			throw new OwlToSqlTransformationException("Illegal expression: "+expressionToTransform);
		
		sql = sql.replaceAll("\\{RESULT_TABLE\\}", baseTable);
		sql = sql.replaceAll("\\{APP_SCHEMA\\}", config.dbAppSchema);
		
		log.info("Transformed SQL: "+sql);
		
		return sql;
		
	}

	private String doPreprocessing(String expressionToTransform) 
	{
		expressionToTransform = expressionToTransform.replaceAll("\t", " ");
		expressionToTransform = expressionToTransform.replaceAll("\n", " ");
		expressionToTransform = expressionToTransform.replaceAll("\r", " ");
		expressionToTransform = expressionToTransform.replaceAll(" {2,}", " ");
		expressionToTransform = expressionToTransform.replaceAll("\\(\\s{1,}", "(");
		expressionToTransform = expressionToTransform.replaceAll("\\s{1,}\\)", ")");
		
		return expressionToTransform;
	}
	
	private void doValidation(String expressionToTransform) throws OwlToSqlTransformationException 
	{
		if(expressionToTransform.contains(" some ") || expressionToTransform.contains(" value "))
			throw new OwlToSqlTransformationException("Illegal expression: "+expressionToTransform);
	}

	@Override
	public String transformOWLClassExpression(OWLClassExpression category) throws OwlToSqlTransformationException 
	{
		ManchesterOWLSyntaxOWLObjectRendererImpl renderer = new ManchesterOWLSyntaxOWLObjectRendererImpl();
		String expressionToTransform = renderer.render(category);
		return transformOWLClassExpression(expressionToTransform);
	}
	
	private String getResultsTableName(String type) throws OwlToSqlTransformationException 
	{
		String key = "DbResultsTable-"+type;
		String r = config.getDbConfig().getProperty(key);
		if(r == null)
			throw new OwlToSqlTransformationException("Unable to determine results table for type: "+type+"; param: "+key);
		else
			return r;
	}
	
	public static void main(String[] args) throws Exception 
	{
//		String category = "Medical_procedure and BUBA1 and HUB2";
//		String category = "Medical_procedure and BUBA1 and not (HUB2 or AAAdA)";
		String category = "Medical_procedure and (OWLClass_66acd20b_7121_4d38_9bf3_f46b0d1f348e or PTest1)  ";
		String configFileName = EventsToSQLP4Transformer.class.getSimpleName().concat(".properties");
		String jarDirectory = new File(EventsToSQLP4Transformer.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath()).getParentFile().getPath();
		CompoundCategoryTransformer ct = new CompoundCategoryTransformer(new DynamicDbAppConfig(jarDirectory.concat(File.separator).concat(configFileName), jarDirectory.concat(File.separator).concat("LinkedFactsP4DbConfig.properties")));
		System.out.println(category);
		String result = ct.transformOWLClassExpression(category);
		System.out.println(result);


	}
}

